//
//  AISSSDPMessage.m
//  AISUPnP
//
//  Created by Ares on 1/26/15.
//  Copyright (c) 2015 Ares. All rights reserved.
//

#import "AISSSDPMessage.h"
#import "AISSSDPCommDef.h"

#define SSDP_MULTICAST_IP @"239.255.255.250"
#define SSDP_MULTICAST_PORT 1900

#define MESSAGE_STARTLINE_SEARCH @"M-SEARCH * HTTP/1.1"
#define MESSAGE_STARTLINE_NOTIFY @"NOTIFY * HTTP/1.1"
#define MESSAGE_STARTLINE_RESPONSE @"HTTP/1.1 200 OK"

#define KEY_MESSAGE_HOST @"Host"

#define KEY_SEARCH_MAN @"Man"
#define KEY_SEARCH_ST @"ST"
#define KEY_SEARCH_MX @"MX"

#define KEY_RESPONSE_DATE @"DATE"

#define KEY_NOTIFY_TYLE @"NT"
#define KEY_NOTIFY_SUB_TYPE @"NTS"

#define KEY_LOCATION @"Location"
#define KEY_UNIQUE_SERVICE_NAME @"USN"
#define KEY_CACHE_CONTROL @"Cache-Control"
#define KEY_CACHE_MAX_AGE @"max-age"
#define KEY_SERVER @"Server"

#define MAN_SSDP_DISCOVER @"ssdp:discover"

#define VALUE_NTS_SSDP_ALIVE @"ssdp:alive"
#define VALUE_NTS_SSDP_UPDATE @"ssdp:update"
#define VALUE_NTS_SSDP_BYEBYE @"ssdp:byebye"


@implementation AISSSDPMessage

- (id)initWithMessage:(NSString *)message fromHost:(NSString *)host andPort:(NSInteger)port
{
    self = [super init];
    if (nil != self)
    {
        _fromHost = host;
        _fromPort = port;
        _rawMessage = message;
        [self parseMessage];
    }
    
    return self;
}

- (void)parseMessage
{
    if (nil == self.rawMessage)
    {
        return;
    }
    
    if ([self.rawMessage rangeOfString:MESSAGE_STARTLINE_SEARCH].length > 0)
    {
        self.messageType = MT_SSDP_SEARCH;
        [self parseSearchMessage];
    }
    else if ([self.rawMessage rangeOfString:MESSAGE_STARTLINE_NOTIFY].length > 0)
    {
        self.messageType = MT_SSDP_NOTIFY;
        [self parseNotifyMessage];
    }
    else if ([self.rawMessage rangeOfString:MESSAGE_STARTLINE_RESPONSE].length > 0)
    {
        self.messageType = MT_SSDP_RESPONSE;
        [self parseResponseMessage];
    }
    else
    {
        self.messageType = MT_UNKNOWN;
        NSLog(@"Unknown Message:\n%@", self.rawMessage);
        
        return;
    }
}

- (void)parseSearchMessage
{
    if (nil == self.rawMessage || MT_SSDP_SEARCH != self.messageType)
    {
        return;
    }
    
    NSArray *lineArray = [self.rawMessage componentsSeparatedByString:@"\r\n"];
    for (NSString *line in lineArray)
    {
        NSRange range = [line rangeOfString:@":"];
        if (range.length < 1)
        {
            continue;
        }
        
        NSString *key = [line substringToIndex:range.location];
        NSString *value = [line substringFromIndex:range.location + range.length];
        value = [value stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
        
        if (NSOrderedSame == [key caseInsensitiveCompare:KEY_MESSAGE_HOST])
        {
            if ([value rangeOfString:SSDP_MULTICAST_IP].length > 0)
            {
                self.multicast = YES;
            }
            else
            {
                self.multicast = NO;
            }
        }
        // for Search Message
        else if (NSOrderedSame == [key caseInsensitiveCompare:KEY_SEARCH_MX])
        {
            self.searchMX = [value integerValue];
        }
        else if (NSOrderedSame == [key caseInsensitiveCompare:KEY_SEARCH_ST])
        {
            self.searchTarget = value;
        }
    }
}

- (void)parseResponseMessage
{
    if (nil == self.rawMessage || MT_SSDP_RESPONSE != self.messageType)
    {
        return;
    }
    
    NSArray *lineArray = [self.rawMessage componentsSeparatedByString:@"\r\n"];
    for (NSString *line in lineArray)
    {
        NSRange range = [line rangeOfString:@":"];
        if (range.length < 1)
        {
            continue;
        }
        
        NSString *key = [line substringToIndex:range.location];
        NSString *value = [line substringFromIndex:range.location + range.length];
        value = [value stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
        
        if (NSOrderedSame == [key caseInsensitiveCompare:KEY_MESSAGE_HOST])
        {
            if ([value rangeOfString:SSDP_MULTICAST_IP].length > 0)
            {
                self.multicast = YES;
            }
            else
            {
                self.multicast = NO;
                NSLog(@"SSDP Host: %@", value);
            }
        }
        // for Search Message
        else if (NSOrderedSame == [key caseInsensitiveCompare:KEY_LOCATION])
        {
            self.location = [self complementURL:value];
        }
        else if (NSOrderedSame == [key caseInsensitiveCompare:KEY_SERVER])
        {
            self.serverType = value;
        }
        else if (NSOrderedSame == [key caseInsensitiveCompare:KEY_SEARCH_ST])
        {
            self.searchTarget = value;
        }
        else if (NSOrderedSame == [key caseInsensitiveCompare:KEY_UNIQUE_SERVICE_NAME])
        {
            self.uniqueServiceName = value;
        }
    }
}

- (void)parseNotifyMessage
{
    if (nil == self.rawMessage || MT_SSDP_NOTIFY != self.messageType)
    {
        return;
    }
    
    NSArray *lineArray = [self.rawMessage componentsSeparatedByString:@"\r\n"];
    for (NSString *line in lineArray)
    {
        NSRange range = [line rangeOfString:@":"];
        if (range.length < 1)
        {
            continue;
        }
        
        NSString *key = [line substringToIndex:range.location];
        NSString *value = [line substringFromIndex:range.location + range.length];
        value = [value stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
        
        if (NSOrderedSame == [key caseInsensitiveCompare:KEY_MESSAGE_HOST])
        {
            if ([value rangeOfString:SSDP_MULTICAST_IP].length > 0)
            {
                self.multicast = YES;
            }
            else
            {
                self.multicast = NO;
                NSLog(@"SSDP Host: %@", value);
            }
        }
        // for Search Message
        else if (NSOrderedSame == [key caseInsensitiveCompare:KEY_UNIQUE_SERVICE_NAME])
        {
            self.uniqueServiceName = value;
        }
        else if (NSOrderedSame == [key caseInsensitiveCompare:KEY_NOTIFY_TYLE])
        {
            self.notifyType = value;
        }
        else if (NSOrderedSame == [key caseInsensitiveCompare:KEY_NOTIFY_SUB_TYPE] && nil != value)
        {
            if (NSOrderedSame == [value caseInsensitiveCompare:VALUE_NTS_SSDP_ALIVE])
            {
                self.notifySubType = NTS_SSDP_ALIVE;
            }
            else if (NSOrderedSame == [value caseInsensitiveCompare:VALUE_NTS_SSDP_UPDATE])
            {
                self.notifySubType = NTS_SSDP_UPDATE;
            }
            else if (NSOrderedSame == [value caseInsensitiveCompare:VALUE_NTS_SSDP_BYEBYE])
            {
                self.notifySubType = NTS_SSDP_BYEBYE;
            }
        }
        else if (NSOrderedSame == [key caseInsensitiveCompare:KEY_LOCATION])
        {
            self.location = [self complementURL:value];
        }
        else if (NSOrderedSame == [key caseInsensitiveCompare:KEY_UNIQUE_SERVICE_NAME])
        {
            self.uniqueServiceName = value;
        }
        else if (NSOrderedSame == [key caseInsensitiveCompare:KEY_CACHE_CONTROL])
        {
            NSArray *valueArray = [value componentsSeparatedByString:@":"];
            if (valueArray.count > 1)
            {
                if ([valueArray[0] isEqualToString:KEY_CACHE_MAX_AGE])
                {
                    self.maxAge = [valueArray[1] integerValue];
                }
            }
        }
        else if (NSOrderedSame == [key caseInsensitiveCompare:KEY_SERVER])
        {
            self.serverType = value;
        }
    }
}

- (NSString *)complementURL:(NSString *)value
{
    NSString *location = nil;
    if ([value hasPrefix:@"http://"])
    {
        location = value;
    }
    else
    {
        location = [NSString stringWithFormat:@"http://%@/%@", self.fromHost, value];
    }
    
    return location;
}

@end
